<?php
/**
 * @version : 1.0
 * @since June-2008
 * @package : lib
 * @subpackage struct
 * @name :  CList
 * @todo:  Lớp  cơ sở CList. Xử lý dữ liệu ở dạng danh sách
*/
class CList
{
	public $items;
	public static $current_orders;
	/**
	 * Hàm construct khởi tạo một danh sách
	 *
	 * @param  $items là các đối tượng trong danh sách
	 */
	function __construct($items=array())
	{
		$this->items = $items;
	}
	/**
	 * Hàm each(): thao tác với từng phần tử của danh sách này (duyệt từng phần tử của mảng)
	 *
	 * @param $func
	 * @return 
	 */
	function &each($func)
	{
		foreach($this->items as &$item)
		{
			if($func($item))
			{
				break;
			}
		}
		return $this;
	}
	/**
	 * Hàm first() thao tác với phần tử đầu tiên của list
	 *
	 * @return trả về items đầu tiên sau khi thiết lập lại 
	 */
	function &first()
	{
		return reset($this->items);
	}
	/**
	 * Hàm next() thao tác với phần tử tiếp theo của danh sách
	 *
	 */
	function next()
	{
		return next($this->items);
	}
	function json()
	{
		return json_encode($this->items);
	}
	/**
	 * Hàm flatten() duyệt  và thao tác các items trong danh sách theo dạng danh sách flatten
	 *
	 * @param  $key
	 * @return $items trả về danh sách các items đã được duyệt
	 */
	function flatten($key = false)
	{
		$items = array();
		foreach($this->items as $id=>&$item)
		{
			if(!$key)
			{
				$key = isset($item['name'])?'name':
						(isset($item['title'])?'title':
						 (isset($item['id'])?'id':false));
			}
			if($key and isset($item[$key]))
			{
				$items[$id] = $item[$key];
			}
		}
		return $items;
	}
	/**
	 * Hàm filter() dùng để lọc có điều kiện
	 *
	 * @param  $conditions điều kiện lọc
	 * @return $new_items trả về các items mới sau khi lọc từ danh sách
	 */
	function filter($conditions)
	{
		$new_items = array();
		if(is_array($this->items))
		{
			foreach($this->items as $id=>&$item)
			{
				if(is_array($conditions))
				{
					if(CRecord($item)->test($conditions))
					{
						$new_items[$id] = $item;
					}
				}
				elseif(!$conditions)
				{
					$new_items[$id] = $item;
				}
				elseif(is_array($item))
				{
					if(isset($item['id']) and $item['id'] == $conditions)
					{
						$new_items[$id] = $item;
					}
				}
				elseif($item == $conditions)
				{
					$new_items[$id] = $item;
				}
			}
		}
		return $new_items;
	}
	/**
	 * Sắp thứ tự các items trong list
	 *
	 * @param $order_by để thao tác sắp xếp
	 * @return $this trả về danh sách được sắp xếp
	 */
	function &order($order_by)
	{
		CList::$current_orders = explode(',', $order_by);
		foreach(CList::$current_orders as $i => $order)
		{
			$dir = 'ASC';
			if(strpos($order, 'DESC') or strpos($order, 'desc'))
			{
				$dir = 'DESC';
			}
			$order = trim(str_ireplace(array(' ASC', ' DESC'), array('', ''),$order));
			CList::$current_orders[$i] = array($order, $dir);
		}
		uasort($this->items, 'item_compare');
		return $this;
	}
	/**
	 * Hàm extract_id() lấy ra một id của một trường trong danh sách
	 *
	 * @param string $field tên trường
	 * @return trả về items được lấy ra khỏi danh sách
	 */
	function extract_id($field)
	{
		$items = array();
		foreach($this->items as &$item)
		{
			if(isset($item[$field]))
			{
				$items[$item[$field]] = $item;
			}
		}
		return $items;
	}
	/**
	 * Hàm group() nhóm các items lại thành một nhóm thông qua việc kiểm tra các trường và id của các items trong danh sách
	 *
	 * @param $field tên trường
	 * @return $groups trả về nhóm được tạo ra trong list các items
	 */
	function group($field)
	{
		$groups = array();
		foreach($this->items as &$item)
		{
			if(isset($item[$field]))
			{
				if(!isset($groups[$item[$field]]))
				{
					$groups[$item[$field]] = array();
				}
				if(isset($item['id']))
				{
					$groups[$item[$field]][$item['id']] = $item;
				}
				else
				{
					$groups[$item[$field]][] = $item;
				}
			}
		}
		return $groups;
	}
}
function CList($items = array())
{
	return new CList($items);
}
function item_compare($a, $b)
{
	foreach(CList::$current_orders as $order)
	{
		if(isset($a[$order[0]]) and isset($b[$order[0]]))
		{
			if(is_numeric($a[$order[0]]) and is_numeric($b[$order[0]]))
			{
				$compare = number_format($a[$order[0]] - $b[$order[0]]);
			}
			else
			{
				$compare = strcmp($a[$order[0]], $b[$order[0]]);
			}
			if($order[1] == 'DESC')
			{
				$compare = - $compare;
			}
			if($compare != 0)
			{
				return $compare;
			}
		}
	}
	return 0;
}
?>